<template>
  <div>
    <el-card style="margin-top: 20px;">
      <template #header>
        <el-button type="primary" size="default" :icon="Plus" @click="showAddTrademark">添加</el-button>
      </template>
      <!-- html中表格按照行走 在element-plus中表格按照列去玩耍 -->
      <!-- el-table展示数据 -->
      <!-- border带边框  stripe斑马纹  data就是要渲染的数据-->
      <el-table :data="trademarkList" border stripe style="margin-bottom: 20px;">
        <!-- el-table-column表格中的每一列 -->
        <!-- 
          label列标题  
          width列宽度 单位是px 但是不需要写上px 没有写width平分天下
          align列对齐方式 center是居中
          type列类型 index代表是序号列 回头默认会从1开始展示
        -->
        <!-- 列暗含遍历 -->
        <!-- prop书写要渲染的属性 -->
        <el-table-column label="序号" width="80" align="center" type="index"></el-table-column>
        <el-table-column label="品牌名称" prop="tmName"></el-table-column>
        <el-table-column label="品牌LOGO">
          <!-- 如果咱们要直接渲染某个数据 那么书写prop属性就够了 如果想要渲染某个结构不可以使用prop了 应该使用作用域插槽 回传了两个数据 row(行 品牌对象) $index 所对应的下标 -->
          <template v-slot="{ row, $index }">
            <el-image :src="row.logoUrl" style="width: 100px;height: 60px;"></el-image>
          </template>
        </el-table-column>
        <el-table-column label="操作">
          <template v-slot="{ row, $index }">
            <el-button type="warning" size="small" :icon="Edit" @click="showUpdateTrademark(row)">修改</el-button>
            <el-button type="danger" size="small" :icon="Delete" @click="deleteTrademark(row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>

      <el-pagination v-model:current-page="page" v-model:page-size="limit" :page-sizes="[3, 5, 7, 9]" :total="total"
        layout="prev, pager, next, jumper,->,sizes,total" @size-change="handleSizeChange"
        @current-change="handleCurrentChange" />

    </el-card>

    <!-- dialogFormVisible在控制对话框的显示和隐藏  title标题-->
    <el-dialog v-model="dialogFormVisible" :title="`${tmForm.id ? '修改' : '添加'}品牌`">
      <!-- table展示数据 form收集数据 -->
      <!-- 
        1.给form增加model属性 (1.指明这个form要收集数据对象 2.收集数据对象里面的属性和规则对象当中的属性是一致的)
        2.给form增加rules
        3.给每一个表单项增加prop属性 值是规则对象当中的某个属性名 代表这个表单项要去应用哪一个规则来去验证
       -->
      <!-- 咱们需要获取到form的组件实例 因为实例身上又很多方法(验证全部方法、清除验证的方法....) -->
      <el-form ref="formEl" :model="tmForm" :rules="rules" style="width:80%">
        <!-- label表单项的文本内容  label-width="100px"文本宽度 带px-->
        <el-form-item label="品牌名称" label-width="100px" prop="tmName">
          <el-input v-model="tmForm.tmName" />
        </el-form-item>
        <el-form-item label="品牌LOGO" label-width="100px" prop="logoUrl">
          <!-- action就是向后端发送请求的地址  show-file-list控制是否是照片墙-->
          <el-upload class="avatar-uploader" :action="`${baseUrl}/admin/product/upload`" :show-file-list="false"
            :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload">
            <img v-if="tmForm.logoUrl" :src="tmForm.logoUrl" class="avatar" />
            <el-icon v-else class="avatar-uploader-icon">
              <Plus />
            </el-icon>
            <template #tip>
              <div class="el-upload__tip">
                上传的图片必须是jpg且不能大于2M
              </div>
            </template>
          </el-upload>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialogFormVisible = false">取消</el-button>
          <el-button type="primary" @click="addOrUpdate">
            确定
          </el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue"
import { ElMessage } from 'element-plus';
export default defineComponent({
  name: 'Trademark',
})
</script>

<script lang="ts" setup>
import { Plus, Edit, Delete } from '@element-plus/icons-vue'
import { ref, onMounted, reactive, nextTick } from 'vue'
import trademarkApi, { type TrademarkData } from '@/api/trademark'
import { ElMessageBox, type FormRules, type UploadProps } from 'element-plus'
const page = ref(1) //当前页码
const limit = ref(3) //每页大小
const total = ref(0) //总数
const trademarkList = ref<TrademarkData[]>([]) //品牌列表
const dialogFormVisible = ref(false)

// 封装函数发送获取品牌列表的请求
async function getPageTmList() {
  try {
    const res = await trademarkApi.getPageList(page.value, limit.value)
    total.value = res.total
    trademarkList.value = res.records
  } catch (error) {
    ElMessage.error('获取品牌列表失败')
  }
}

onMounted(() => {
  getPageTmList()
})

// 每页大小变化自动执行的回调函数
function handleSizeChange(num: number) { //形参默认接收最新页大小
  limit.value = num
  getPageTmList()
}
// 当前页变化自动执行的回调函数
function handleCurrentChange(num: number) {//形参默认接收最新当前页码
  page.value = num
  getPageTmList()
}
// 点击添加显示对话框
function showAddTrademark() {
  // 在vue中更新是同步的还是异步的 
  // 数据的更新是同步的 页面的更新是异步的(微任务 promise.then)

  // 显示对话框
  dialogFormVisible.value = true
  // 为了解决再次点击添加还显示上次的数据 要去清空一下
  tmForm.value = {
    tmName: '',
    logoUrl: ''
  }
  // 去清除掉之前的那些验证
  // nextTick某次数据变化后 并且这次页面也更新成功才去执行里面的回调函数
  nextTick(() => {
    formEl.value.clearValidate()  //不传默认清除所有
  })
}
// 点击修改显示对话框
// 点击添加和点击修改 显示的是同一个对话框
// 点击添加那些数据应该都是空的 点击修改的话是有数据的回显的
// 点击添加的时候那个数据和修改的数据是不是同一个对象??? 不是同一个 添加数据tmForm(初始化的那个) 修改数据是row
// 添加时里没有id  修改时有id
function showUpdateTrademark(row: TrademarkData) {
  // 显示对话框
  dialogFormVisible.value = true
  // 回显数据
  tmForm.value = { ...row }
  // 去清除掉之前的那些验证
  nextTick(() => {
    formEl.value.clearValidate()  //不传默认清除所有
  })

  // 出现问题: 因为直接把row赋值给tmForm  两个人指向同一个对象 修改(v-model)tmForm中的tmName  导致row.tmForm也变
  // 拷贝: 要出现新的空间对象地址
  // 分类: 浅拷贝深拷贝
  // let obj = {a:1,b:2}
  // let obj2 = obj  //赋值不是拷贝！！！
  // let a = 1
  // let b = a  //基本数据类型不涉及拷贝!!!
  // let obj = { a: 1, b: 2 }
  // let obj2 = { ...obj } 
  // 浅拷贝: 只考虑最外层的地址是一个新的地址
  // let obj = { a: 1, b: { c: 2 } }
  // let obj2 = { ...obj }
  // 深拷贝: 不光考虑最外层的地址是一个新的地址  还要考虑里面的每一个属性如果是引用数据  也需要出现新的空间地址
}
// 添加或修改的请求逻辑
async function addOrUpdate() {
  // 应该去看用户输入的每项内容是否都合法 都合法再去发送请求 但凡有一个不合法就应该提示
  try {
    await formEl.value.validate() //都符合返回成功promise  有一项不符合返回失败promise
    // 1.拿到发送请求要给到后端的那个数据(收集的数据)
    let trademark = tmForm.value
    // 2.自己所收集的数据对象要求可能和后端要求传递的那个参数对象不一样 不一样就需要整理参数 一样就不整理
    // 3.发送请求
    try {
      await trademarkApi.addOrUpdate(trademark)
      // 4.请求成功  提示 关弹窗 重新获取最新列表(添加获取第一页 修改获取当前页)
      ElMessage.success(`${trademark.id ? '修改' : '添加'}品牌成功`)
      dialogFormVisible.value = false
      if (!trademark.id) { //添加
        page.value = 1
      }
      getPageTmList()
    } catch (error) {
      // 5.请求失败
      ElMessage.error(`${trademark.id ? '修改' : '添加'}品牌失败`)
    }
  } catch (error) {

  }
}
// 删除品牌的逻辑
function deleteTrademark(row: TrademarkData) {
  // 参数1 内容    参数2 标题    参数3 配置对象
  // 返回值是一个promise  点击确定返回成功promise  点击取消返回失败promise
  ElMessageBox.confirm(
    `确定要删除 ${row.tmName} 这个品牌吗?`,
    '警告',
    {
      confirmButtonText: '确定', //确定按钮的文本
      cancelButtonText: '取消', //取消按钮的文本
      type: 'warning', //类型
    }
  )
    .then(async () => { //成功 点击确定
      try {
        await trademarkApi.deleteTrademark(row.id as number)
        // 删除成功 提示
        ElMessage.success('删除成功')
        // 如果当前页列表只有一个了 删除完后需要请求前一页  当前页列表不是只有一个 请求当前页就可以
        if (trademarkList.value.length === 1) {
          page.value -= 1
        }
        getPageTmList()
      } catch (error) {
        // 删除失败
        ElMessage.error('删除失败')
      }
    })
    .catch(() => { //失败 点击取消
      ElMessage.info('取消删除')
    })
}

// 添加品牌的逻辑 首先需要收集用户输入或选择的一些数据 拼装为一个后端想要的数据 向后端发送请求 让他把这个数据增加到数据库中
const tmForm = ref<TrademarkData>({
  tmName: '',
  logoUrl: ''
})
// 引入全局变量的环境
const baseUrl = import.meta.env.VITE_API_URL

// 自定义品牌名称的验证函数
function validateTmName(rule: any, value: any, callback: any) {
  // rule 规则对象, value用户所输入的呢容, callback验证成功或失败的回调函数  callback调用的时候不传参 代表验证成功 调用的时候传参 代表验证失败 传递的参数通常是错误消息
  if (value.length < 2 || value.length > 10) { //不合法 
    callback('品牌名称长度必须是2-10之间')
  } else { //合法
    callback()
  }
}
// 获取form实例
const formEl = ref()
// 表单要去使用的规则对象
const rules = reactive<FormRules>({
  // 属性名需要和谁一致???  需要和收集数据的属性的名字一致
  // 属性值是一个数组 数组中可以放置一个又一个关于这个表单项所要使用的规则(对象)
  tmName: [
    // required必填的  message错误的提示 trigger触发方式(blur失去焦点触发 change输入内容)
    { required: true, message: '品牌名称必须填写', trigger: 'blur' },
    // 内置规则
    // { min: 2, max: 10, message: '品牌名称长度须是2-10之间', trigger: 'change' },
    // 自定义规则
    // validator验证器的意思 咱们需要书写对应的验证函数 来去完成校验
    { validator: validateTmName, trigger: 'change' }
  ],
  logoUrl: [
    // upload他不是表单元素 所以没有办法在此刻验证  在完整校验可以校验上
    { required: true, message: '品牌LOGO必须上传', trigger: 'change', }
  ],
})

// 上传成功的回调
const handleAvatarSuccess: UploadProps['onSuccess'] = (
  response,
  uploadFile
) => {
  tmForm.value.logoUrl = response.data
  // 清除图片的验证规则
  formEl.value.clearValidate('logoUrl') //当中传递rules当中的某个属性名
}
// 上传之前执行的回调
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
  // console.log(rawFile,'rawFile') //上传图片对象
  if (rawFile.type !== 'image/jpeg') {
    ElMessage.error('图片LOGO必须是jpeg格式!')
    return false
    // 1mb === 1024kb  1kb === 1024B（byte）  1B === 8b(bit)
  } else if (rawFile.size / 1024 / 1024 > 2) {
    ElMessage.error('图片LOGO大小不能超过2MB!')
    return false
  }
  // 回调函数retrun true上传 return false不上传
  return true
}
</script>

<style scoped>
.avatar-uploader .avatar {
  width: 178px;
  height: 178px;
  display: block;
}
</style>

<style>
.avatar-uploader .el-upload {
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
}

.avatar-uploader .el-upload:hover {
  border-color: var(--el-color-primary);
}

.el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  text-align: center;
}
</style>